import {
  Canvas,
  FabricObject,
  Group,
  IText,
  Line,
  Point
} from 'fabric'
import { Vector2 as v2 } from '../math/Vector2'

export default class Two {
  canvas: Canvas
  width: number
  height: number
  grid: Group
  points: v2[]
  showAxes: boolean
  size: v2
  scale: number
  offset: v2
  space: number
  padding: number
  pointsX: v2[]
  pointsY: v2[]
  constructor(el: HTMLCanvasElement) {
    this.showAxes = true
    this.width = 1200
    this.height = 800
    this.space = 20
    this.padding = this.space * 10
    this.size = new v2(this.width, this.height).addScalar(this.padding * 2)
    this.offset = this.size.clone().sub(new v2(this.width, this.height)).multiplyScalar(-0.5)

    this.scale = 1
    this.grid = new Group()
    this.pointsX = []
    this.pointsY = []

    this.canvas = new Canvas(el, {
      width: this.width,
      height: this.height,
      selection: false,
      devicePixelRatio: window.devicePixelRatio || 1,
    })
  }
  init() {
    this.createLines()
    this.setEvents()
  }
  findObjectWithProp(parant: FabricObject, prop: string, value: string) {
    // @ts-ignore
    return parant.getObjects().find(v => v.get(prop) === value)
  }
  setEvents() {
    let scale = 1
    this.canvas.on('mouse:wheel', (event) => {
      const count = event.e.deltaY > 0 ? -1 : 1

      scale += count * 0.1

      if (scale <= 1) scale = 1.8
      else if (scale > 1.8) scale = 1

      this.scale = scale

      this.createLines()
    })
    let enable = false, origin = new v2(), offset = new v2()
    this.canvas.on('mouse:down', (event) => {
      offset.set(0, 0)
      origin.set(event.viewportPoint.x, event.viewportPoint.y)
      enable = true
    })
    this.canvas.on('mouse:move', (event) => {
      if (!enable) return

      const p1 = event.viewportPoint.subtract(origin)

      offset.set(p1.x, p1.y)
      this.pointsX.forEach(e => {
        e.add(offset)
      })
      this.pointsY.forEach(e => {
        e.add(offset)
      })

      const firstPoint = this.pointsX[0]

    })
    this.canvas.on('mouse:up', (event) => {
      if (!enable) return


      enable = false
    })
  }
  createPoints(
    size?: v2,
    space?: number
  ) {
    size = size || new v2(this.width, this.height)
    space = typeof space == 'undefined' ? 20 : space

    const w = size.x
    const h = size.y
    const distance = space * 5
    const lengthX = Math.ceil(w / distance)
    const lengthY = Math.ceil(h / distance)

    for (let i = 0; i < lengthX; i++) {
      const point = new v2(i * distance, h / 2)

      this.pointsX.push(point)
    }
    for (let i = 0; i < lengthY; i++) {
      const point = new v2(w / 2, i * distance)

      this.pointsY.push(point)
    }

    const boxInfo = {
      size,
      space,
      width: size.x,
      height: size.y,
      center: size.multiplyScalar(0.5)
    }

    return { pointsX: this.pointsX, pointsY: this.pointsY, boxInfo }
  }
  createLines() {
    const { pointsX, pointsY, boxInfo } = this.createPoints(this.size, this.space)
    const { width, height, space, center } = boxInfo

    const options = {
      stroke: '#000',
      strokeWidth: 0.2,
      evented: false
    }
    const subOption = {
      stroke: '#000',
      strokeWidth: 0.1,
      evented: false
    }
    const centenrOption = {
      stroke: '#000',
      strokeWidth: 2,
      evented: false
    }

    const horizontal = [], vertical = [], textList = []
    for (let i = 0; i < pointsX.length; i++) {
      const { x, y } = pointsX[i]
      const text = new IText(`x${i}`, {
        left: x,
        top: y,
        stroke: '#000',
        fontSize: 16,
        evented: false
      })
      textList.push(text)

      if (this.showAxes) {
        const line = new Line([x, 0, x, height], options)
        horizontal.push(line)
        for (let j = 1; j < 5; j++) {
          const line = new Line([x + space * j, 0, x + space * j, height], subOption)
          horizontal.push(line)
        }
      }
    }
    for (let i = 0; i < pointsY.length; i++) {
      const { x, y } = pointsY[i]
      const text = new IText(`y${i}`, {
        left: x,
        top: y,
        stroke: '#000',
        fontSize: 16,
        evented: false
      })

      textList.push(text)
      if (this.showAxes) {
        const line = new Line([0, y, width, y], options)
        vertical.push(line)
        for (let j = 1; j < 5; j++) {
          const line = new Line([0, y + space * j, width, y + space * j], subOption)
          vertical.push(line)
        }
      }

    }

    const axisX = new Line([0, center.y, width, center.y], centenrOption)
    const axisY = new Line([center.x, 0, center.x, height], centenrOption)

    this.grid && this.canvas.remove(this.grid)
    this.grid = new Group()
    this.grid.hasControls = false
    this.grid.hasBorders = false
    this.grid.evented = false
    this.grid.add(...horizontal, ...vertical)

    this.grid.add(axisX, axisY, ...textList)
    this.grid.setX(this.offset.x)
    this.grid.setY(this.offset.y)

    // this.grid.scale(this.scale)
    this.canvas.add(this.grid)
  }
  addLines(type: 'x' | 'y', point: v2) {
    const { size, space, width } = this
    const lines = []
    const options = {
      stroke: '#000',
      strokeWidth: 0.2,
      evented: false
    }
    const subOption = {
      stroke: '#000',
      strokeWidth: 0.1,
      evented: false
    }
    if (type === 'x') {
      const height = size.y

      const { x, y } = point
      const text = new IText(`x${x}`, {
        left: x,
        top: y,
        stroke: '#000',
        fontSize: 16,
        evented: false
      })

      if (this.showAxes) {
        const line = new Line([x, 0, x, height], options)
        lines.push(line)
        for (let j = 1; j < 5; j++) {
          const line = new Line([x + space * j, 0, x + space * j, height], subOption)
          lines.push(line)
        }
      }

      this.grid.add(...lines, text)
    }
    if (type === 'y') {
      const { x, y } = point
      const text = new IText(`y${y}`, {
        left: x,
        top: y,
        stroke: '#000',
        fontSize: 16,
        evented: false
      })

      if (this.showAxes) {
        const line = new Line([0, y, width, y], options)
        lines.push(line)
        for (let j = 1; j < 5; j++) {
          const line = new Line([0, y + space * j, width, y + space * j], subOption)
          lines.push(line)
        }
      }

      this.grid.add(...lines, text)
    }
  }
  createFnLine() {

  }
  makeGrid() {
    const svg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="100%">
      <defs>
        <pattern id="Pattern" x="0" y="0" width="40" height="40" patternUnits="userSpaceOnUse">
          <line stroke="#ccc" fill="transparent" x1="39" y1="0" x2="39" y2="40"></line>
          <line stroke="#ccc" fill="transparent" x1="0" y1="39" x2="40" y2="39"></line>
        </pattern>
      </defs>
      <rect fill="url(#Pattern)" x="0" y="0" width="100%" height="100%"></rect>
    </svg>`

    const base64 = window.btoa(svg)
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    const width = 1200
    const height = 800
    canvas.width = width
    canvas.height = height
    canvas.style.width = width + 'px'
    canvas.style.height = height + 'px'
    document.body.appendChild(canvas)

    const image = new Image()
    image.src = `data:image/svg+xml;base64,${base64}`
    image.onload = () => {
      const pattern = ctx.createPattern(image, 'repeat')
      ctx.fillStyle = pattern
      ctx.fillRect(0, 0, canvas.width, canvas.height)
    }
  }
}
